"use client";
import { useImperativeHandle, useRef, useState } from "react";
import SmallText from "../../UI/SmallText";
import { DefaultChildrenProps, Mime, UploadProgressProps, UploadProps, UploadRef } from "./type";
import { CloudUploadOutlined } from "@ant-design/icons";
import { cn, destroyTip, showMdTip, showTip, sleep, toFixAndFloat } from "@/lib/util";
import { getAllowStrArr, judgeFiles, uploadToServer } from "./handler";
import { stopUpload, uploadBySlice } from "./sliceUpload";
import { Button, Progress, Tooltip, message } from "antd";
import myForwardref from "@/app/(dashboard)/common/other/myForwardref";

/**自己封装的一个上传组件。 支持分片上传 */
const Upload = myForwardref<UploadProps, UploadRef>(function (props, ref) {
  const {
    children,
    allowType,
    maxSize,
    beforeUpload,
    // maxCount = 1,
    multiple = false,
    className,
    style,
    url,
    disabled = false,
    onSuccess,
    onFail,
    disabledTip,
    needSlice = false,
    targetPath = "other",
    sliceSize = 2 * 1024 * 1024,
    judgeImageRatio,
    judgeVideoRatio,
  } = props;
  /**Input的ref */
  const inputRef = useRef<HTMLInputElement>(null);
  const [progress, setProgress] = useState(0); // 进度条，小于0显示错误，大于100显示成功
  const [showprogress, setShowProgress] = useState(false); //是否显示进度条模块。 开始上传了才显示，上传成功后持续显示一小会
  const [tip, setTip] = useState(""); //上传的提示
  const [messageApi, contextHolder] = message.useMessage();

  /**ownFileName数组，每个元素索引对应上传文件列表files索引 传入ownFileName时会在路径后额外拼接自定义字符串，ai换脸模块专用，特殊需求） */
  let ownFileName: string[] = []
  const setOwnFileName = (_ownFileName: string[]) => {
    ownFileName = _ownFileName
  }
  /**分片上传时会有这个，拿到文件的md5，可以用来取消上传 */
  const md5Ref = useRef<string>();
  /**input上传事件 */
  const onUpload = async (files: FileList | null) => {
    try {
      if (disabled || showprogress) return;
      console.log(files);
      if (!files || files.length === 0) return;
      await judgeFiles(files, allowType, maxSize, judgeImageRatio, judgeVideoRatio);
      if (beforeUpload && (await beforeUpload(files, setOwnFileName)) === false) return;
      await upload(files);
    } catch (error: any) {
      console.error("input上传事件", error);
      showMdTip(error, "error", 3);
      onFail && onFail(error);
    } finally {
      if (inputRef.current) inputRef.current.value = ""; //防止二次上传相同文件导致失败
    }
  };
  /**组件自带上传部分中 - 更新进度条并弹窗 */
  const updateProgress = (nowProgress: number, key: number) => {
    setProgress(nowProgress);
    messageApi.open({
      content: `正在上传中 ${nowProgress}%`,
      key,
      type: "loading",
      duration: 0,
    });
  };
  /**组件自带上传部分 */
  const upload = async (files: FileList | File[]) => {
    const key = Date.now();
    try {
      if (disabled) return;
      messageApi.open({
        content: `正在上传中 ${progress}%`,
        key,
        type: "loading",
        duration: 0,
      });
      setShowProgress(true);
      let res: any;
      //根据是否需要切片，走不同逻辑
      if (needSlice) {
        console.log(ownFileName);
        //根据是否多文件上传，走不同逻辑
        if (multiple) {
          for(let i = 0; i < files.length; i ++) {
            const file = files[i]
            //注意，这个ownfilename是ai换脸模块特有的，设置了ownFileName后会更改返回图片的路径
            const _res = ownFileName.length !== 0 ? await uploadBySlice(
              file,
              targetPath,
              sliceSize,
              (md5) => (md5Ref.current = md5),
              setTip,
              (p) => updateProgress(toFixAndFloat(p * 100), key),
              ownFileName[i],
            ) : await uploadBySlice(
              file,
              targetPath,
              sliceSize,
              (md5) => (md5Ref.current = md5),
              setTip,
              (p) => updateProgress(toFixAndFloat(p * 100), key)
            )
            if (res) {
              res = [...res, _res]
            } else {
              res = [_res]
            }
          }
        } else {
          res = ownFileName.length !== 0 ? await uploadBySlice(
            files[0],
            targetPath,
            sliceSize,
            (md5) => (md5Ref.current = md5),
            setTip,
            (p) => updateProgress(toFixAndFloat(p * 100), key),
            ownFileName[0],
          ) : await uploadBySlice(
            files[0],
            targetPath,
            sliceSize,
            (md5) => (md5Ref.current = md5),
            setTip,
            (p) => updateProgress(toFixAndFloat(p * 100), key)
          );
        }
      } else {
        if (!url) throw "没传递url";
        res = await uploadToServer(url, files, (e) => updateProgress(toFixAndFloat((e.progress || -1) * 100), key));
      }
      onSuccess && (await onSuccess(res));
      showTip("上传成功");
      return res;
    } catch (error: any) {
      setTip(error);
      setProgress(-1);
      showMdTip(error, "error", 3);
      return Promise.reject(error);
    } finally {
      await sleep(1500); //等一会再关闭显示
      messageApi.destroy(key);
      setProgress(0);
      setShowProgress(false);
    }
  };
  /**点击取消分片上传 （普通上传暂不支持） */
  const stop = () => {
    if (md5Ref.current) {
      stopUpload(md5Ref.current);
    }
  };

  useImperativeHandle(ref, () => ({ upload, stop })); //暴露出内部方法

  return (
    <Tooltip title={disabled && disabledTip}>
      <div
        className={cn("relative group/upload", className, disabled && "cursor-not-allowed opacity-70", !showprogress && "cursor-pointer")}
        style={style}
        onClick={() => !disabled && !showprogress && inputRef.current!.click()} //点击div就相当于点击input
        onDragEnter={(e) => e.preventDefault()} //阻止默认事件，就能允许拖拽api了
        onDragOver={(e) => e.preventDefault()} //阻止默认事件，就能允许拖拽api了
        onDrop={(e) => {
          e.preventDefault(); //阻止默认事件，不然会自动下载文件了
          onUpload(e.dataTransfer.files); //拿到拖动到这里的所有文件
        }}
      >
        <div className="w-full h-full">{children || <DefaultChildren show={!showprogress} {...props} />}</div>
        {!children && <UploadProgress showprogress={showprogress} progress={progress} tip={tip} stop={stop} needSlice={needSlice} />}
        <input
          type="file"
          style={{ display: "none" }} //最高优先级
          ref={inputRef}
          onChange={(e) => onUpload(e.target.files)}
          multiple={multiple}
          accept={allowType?.join(",")}
        />
      </div>
      {contextHolder}
    </Tooltip>
  );
});
export default Upload;
/**没填写孩子时，默认的孩子样式 */
function DefaultChildren({
  allowType,
  maxSize,
  show,
  disabled,
  placeholder = "点击或拖拽上传",
  icon,
  maxSizeTip,
  allowTypeTip,
  Icon = CloudUploadOutlined,
}: DefaultChildrenProps) {
  return (
    <div
      className={cn(
        "flexCenter flex-col w-full h-full p-2 border-2 opacity-0 border-dashed rounded-md transition-all",
        show && "opacity-100",
        !disabled && "group-hover/upload:border-blue-300"
      )}
    >
      <div className="w-[100px] h-[100px] flexCenter">{icon || <Icon style={{ fontSize: 60 }} />}</div>
      <SmallText size={16}>{placeholder}</SmallText>
      <div className="flex">
        {allowType && allowTypeTip !== "" && (
          <SmallText className="mx-1" size={12}>
            {allowTypeTip == undefined ? `只允许 ${getAllowStrArr(allowType).join(", ")} 类型` : allowTypeTip}
          </SmallText>
        )}
        {maxSize && maxSizeTip !== "" && (
          <SmallText className="mx-1" size={12}>
            {maxSizeTip == undefined ? `最大 ${maxSize} MB` : maxSizeTip}{" "}
          </SmallText>
        )}
      </div>
    </div>
  );
}
/**上传时的进度条部分 */
function UploadProgress({ showprogress, progress, tip, stop, needSlice }: UploadProgressProps) {
  const status = progress < 0 ? "exception" : progress >= 100 ? "success" : "active";
  return (
    <div
      className={cn(
        "absoluteFull flexCenter opacity-0 transition-all duration-500 flex-col overflow-hidden -z-10",
        showprogress && "opacity-100 z-10"
      )}
    >
      <Progress percent={progress} type="circle" status={status} size={"small"} />
      <SmallText>{tip}</SmallText>
      {needSlice && (
        <Button danger type="text" onClick={stop} disabled={!showprogress}>
          取消上传
        </Button>
      )}
    </div>
  );
}
